/*
 * @Author: your name
 * @Date: 2021-04-10 12:07:01
 * @LastEditTime: 2021-04-12 11:14:17
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \TypeScript\19-高级类型.ts
 */
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var UIElement = /** @class */ (function () {
    function UIElement() {
    }
    UIElement.prototype.animate = function (dx, dy, easing) {
        if (easing === "ease-in") {
            // ...
        }
        else if (easing === "ease-in-out") {
        }
        else if (easing === "ease-out") {
        }
        else {
            // error!shoule not pass null or undefined.
        }
    };
    return UIElement;
}());
var button = new UIElement();
button.animate(0, 0, "ease-in");
// ...more overloads ...
function createElement(tagName) {
    // ...code goew here ...
    return;
}
// 数字字面量类型
// typescript 还具有 数字字面量类型
function rollDie() {
    return;
}
function area(s) {
    switch (s.kind) {
        case "Square": return s.size * s.size;
        case "Circle": return Math.PI * Math.pow(s.radius, 2);
        case "rectangle": return s.width * s.height;
    }
}
function area2(s) {
    switch (s.kind) {
        case "Square": return s.size * s.size;
        case "Circle": return Math.PI * Math.pow(s.radius, 2);
        case "rectangle": return s.width * s.height;
        // 此处需要跟上新增的Triangle，不然不起作用，单数typescript是不会报错的
        // 因为此处要是传入的s是typescript类型的，那么函数area会返回一个undefined是any类型的子类型，所有默认不报错
        default: return s.kind + "-" + s.val;
    }
}
function area3(s) {
    switch (s.kind) {
        case "Square": return s.size * s.size;
        case "Circle": return Math.PI * Math.pow(s.radius, 2);
        case "rectangle": return s.width * s.height;
        // 此处需要跟上新增的Triangle，不然不起作用，单数typescript是不会报错的
        // 因为此处要是传入的s是typescript类型的，那么函数area会返回一个undefined是any类型的子类型，所有默认不报错
        // default: return s.kind + "-" + s.val
    }
}
function assertNever(x) {
    throw new Error("Unexpected object:" + x);
}
function area4(s) {
    switch (s.kind) {
        case "Square": return s.size * s.size;
        case "Circle": return Math.PI * Math.pow(s.radius, 2);
        case "rectangle": return s.width * s.height;
        // default: return assertNever(null);// error here if there are missing cases
    }
}
// assertNever检查 s是否为never类型-即为去除所有可能情况后剩下的类型。如果你忘记某个case，
// 那么s将具有一个真实的类型并且你会得到一个错误。这种方式需要你定义一个额外的函数，
// 但是在你忘记某个case的时候也更加明显
// 多态的this类型检查
// 多态的 this类型表示的是某个包含类或接口的子类型。这被称作F-bounded多态性。
// 它能很容易的表现连贯接口间的继承(即所谓的链式操作)
// 比如。在计算器的例子里，在每个操作之后都返回this类型或是jquery函数返回的类型
var BasicCalculator = /** @class */ (function () {
    function BasicCalculator(value) {
        if (value === void 0) { value = 0; }
        this.value = value;
    }
    BasicCalculator.prototype.currentValue = function () {
        return this.value;
    };
    BasicCalculator.prototype.add = function (operand) {
        this.value *= operand;
        return this;
    };
    BasicCalculator.prototype.multiply = function (operand) {
        this.value *= operand;
        return this;
    };
    return BasicCalculator;
}());
var v = new BasicCalculator(2)
    .multiply(5)
    .add(1)
    .currentValue();
// 多态的this类型检查
// 由于前页的BasicCalculator这个类使用了this类型，你可以继承它，
// 新的类可以直接使用之前额方法，不需要做任何的改变
var ScientificCalculator = /** @class */ (function (_super) {
    __extends(ScientificCalculator, _super);
    function ScientificCalculator(value) {
        if (value === void 0) { value = 0; }
        return _super.call(this, value) || this;
    }
    ScientificCalculator.prototype.sin = function () {
        this.value = Math.sin(this.value);
        return this;
    };
    return ScientificCalculator;
}(BasicCalculator));
var v2 = new ScientificCalculator(2)
    .multiply(5)
    .sin()
    .add(1)
    .currentValue();
// 如果没有this类型，
// ScientificCalculator就不能够在继承 BasicCalculator的同时还保持接口的连贯性
// 索引类型
// 使用索引类型，编译器就能够检查使用了动态属性名的代码
// 例如：一个产概念的JavaScript模式就是从对象中选取属性的子集
function pluck(o, names) {
    return names.map(function (n) { return o[n]; });
}
// 下面是如何在typescript里使用此函数，通过搜索引类型查询和索引访问操作符:
function pluck2(o, names) {
    return names.map(function (n) { return o[n]; });
}
var person = {
    name: 'jarid',
    age: 35
};
var strings = pluck(person, ['name']); //ok,string[] 
// 编译器会见擦name是否着呢是Person的一个属性，上页示例还引入了几个新的类型操作符。
// 首先是keyof T，索引类型查询操作符，对于任何类型 T，keyof T的结果为 T 上已知的公共属性名的联合
var personProps; //"name"|"age"
// keyof Person是完全可以与 "name" | "age" 互相替换的，不同的是如果你添加了其他的属性到Person，
// 例如addrss：string，那么keyof Person会自动变为 "name" | "age" | "address"
// 你可以在向pluck函数这类上下文里使用 keyof 因为在使用之前你并不清楚可能出现的属性名。但编译器会检查你是否出了正确的属性名给pluck;
// 索引类型(Index types)之索引访问操作符
// 操作符是T[k]，索引访问操作符
// 在这里，类型语法反映了表达式语法。这意味着person['name']具有类型Person['name'],在我们的例子里则为string类型
// 然而，就像索引类型查询一样，你可以在普通的上下文里使用T[k],这正是它的强大所在，你只要确保类型变量K extends keyof T就可以了
// 例如下面 getProperty函数的例子：
function getProperty(o, name) {
    return o[name]; // o.name is of type T[K]
}
// getProperty里的o:T和name:K,意味着o[name]:T[K]。当你返回T[K]的结果，编译器会实例化键的真实类型，因此getProperty的返回值类型会随着你需要的属性改变
var name1 = getProperty(person, 'name');
var age = getProperty(person, 'age');
var keys; //string
var value; //number
